package io.modifier.basic.compose.animation

import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.rotate
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.modifier.basic.compose.animation.transition.EaseInOut
import io.modifier.basic.compose.animation.transition.fractionTransition
import io.modifier.basic.compose.theme.appColors
import io.modifier.basic.compose.theme.themeAdapter
import kotlin.math.min

/**
 * 加载菊花
 */
@Composable
fun LoadingSpinner(
    modifier: Modifier = Modifier,
    durationMillis: Int = 1000,
    size: Dp = 30.dp,
    color: Color = MaterialTheme.appColors.appColor,
    num: Int = 12,
    play: Boolean = true,
    rotateWhole: Boolean = false
) {
    if (rotateWhole) {
        LoadingSpinnerRotateWhole(modifier, durationMillis, size, color, num, play)
    } else {
        LoadingSpinnerAlphaItem(modifier, durationMillis, size, color, num)
    }
}

@Composable
private fun LoadingSpinnerAlphaItem(
    modifier: Modifier = Modifier,
    durationMillis: Int = 1000,
    size: Dp = 30.dp,
    color: Color = MaterialTheme.appColors.appColor,
    num: Int = 12
) {

    val transition = rememberInfiniteTransition()

    val alphaList = remember { mutableListOf<State<Float>>() }

    alphaList.clear()
    repeat(num) {
        val realIndex = it - 1
        val alpha = transition.fractionTransition(
            initialValue = 1f,
            targetValue = 0.15f,
            durationMillis = durationMillis,
            offsetMillis = durationMillis / num * realIndex,
            easing = EaseInOut
        )
        alphaList.add(alpha)
    }


    Box(
        modifier = Modifier
            .size(size),
        contentAlignment = Alignment.Center
    ) {

        Canvas(
            modifier = modifier
                .background(Color(0x17868686).themeAdapter(), CircleShape)
                .padding(size / 10)
                .size(size / 10 * 9)
                .rotate(-90f)
        ) {
            val rectSize = Size(width = this.size.width / 6, height = this.size.height / 40)
            for (i in 0 until num) {
                rotate(360f / num * i) {
                    drawRect(
                        color = color.copy(alpha = alphaList[i].value),
                        topLeft = center + Offset(x = rectSize.width * 1.8f, y = 0f),
                        size = rectSize,
                        style = Stroke(
                            width = rectSize.height * 2,
                            pathEffect = PathEffect.cornerPathEffect(rectSize.height)
                        )
                    )
                }
            }
        }

    }

}

@Composable
private fun LoadingSpinnerRotateWhole(
    modifier: Modifier = Modifier,
    durationMillis: Int = 1000,
    size: Dp = 20.dp,
    color: Color = MaterialTheme.appColors.appColor,
    num: Int = 12,
    play: Boolean = true,
) {

    val alphaUnit = remember {
        (1f - 0.15f) / num
    }

    val rotateDegree = remember {
        Animatable(-90f)
    }

    LaunchedEffect(key1 = play) {
        if (play) {
            rotateDegree.animateTo(
                targetValue = 360f * 2,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        durationMillis = durationMillis * 2,
                        easing = LinearEasing
                    )
                )
            )
        }
    }

    Box(
        modifier = Modifier
            .size(size),
        contentAlignment = Alignment.Center
    ) {

        Canvas(
            modifier = modifier
                .background(Color(0x17868686).themeAdapter(), CircleShape)
                .padding(size / 10)
                .size(size / 10 * 9)
                .rotate(rotateDegree.value)
        ) {
            val rectSize = Size(width = this.size.width / 6, height = this.size.height / 40)
            for (i in 0 until num) {

                rotate(360f / num * i) {
                    drawRect(
                        color = color.copy(alpha = min(alphaUnit * (i + 1), 1f)),
                        topLeft = center + Offset(x = rectSize.width * 1.8f, y = 0f),
                        size = rectSize,
                        style = Stroke(
                            width = rectSize.height * 2,
                            pathEffect = PathEffect.cornerPathEffect(rectSize.height)
                        )
                    )
                }

            }
        }

    }

}

@Preview(showSystemUi = true, showBackground = true, backgroundColor = 0xffffffff)
@Composable
fun RenderPreView() {
    LoadingSpinner()
}
